package com.vision.core.cl.ui;

import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.place.shared.PlaceChangeEvent;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.ValueProvider;
import com.sencha.gxt.data.shared.IconProvider;
import com.sencha.gxt.data.shared.ModelKeyProvider;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.BoxLayoutContainer.BoxLayoutPack;
import com.sencha.gxt.widget.core.client.container.HBoxLayoutContainer.HBoxLayoutAlign;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler;
import com.sencha.gxt.widget.core.client.menu.Item;
import com.sencha.gxt.widget.core.client.menu.Menu;
import com.sencha.gxt.widget.core.client.menu.MenuItem;
import com.sencha.gxt.widget.core.client.toolbar.SeparatorToolItem;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;
import com.vision.core.cl.AppPlace;
import com.vision.core.cl.Callback;
import com.vision.core.cm.data.TaskNode;
import com.vision.core.cm.data.TaskNode.NodeType;
import com.vision.core.cm.serv.rpc.MenuServiceAsync;

/**
 * 
 * @author Mark
 *
 */
public class ToolbarMenuViewImpl implements IsWidget, MenuView {
	
	interface Binder extends UiBinder<Widget, ToolbarMenuViewImpl> { }

	private static final Binder binder = GWT.create(Binder.class);
	
	private Presenter presenter;
	
	private MenuServiceAsync menuService;
	
	@UiField
	ToolBar toolbar;
	
	private IconProvider<TaskNode> iconProvider;
	
	public ToolbarMenuViewImpl(MenuServiceAsync menuService, IconProvider<TaskNode> iconProvider) {
		this.menuService = menuService;
		this.iconProvider = iconProvider;
	}
	
	@Override
	public Widget asWidget() {
		toolbar = (ToolBar) binder.createAndBindUi(this);
		toolbar.setHorizontalSpacing(3);
		toolbar.setHeight(28);		
		toolbar.setHBoxLayoutAlign(HBoxLayoutAlign.MIDDLE);
		toolbar.setPack(BoxLayoutPack.CENTER);

		// Load data
		Scheduler.get().scheduleDeferred(new ScheduledCommand() {
			@Override
			public void execute() {
				loadData();		
			}
		});
				
		return toolbar;
	}
	
	protected void loadData() {
		final SelectHandler buttonHandler = new SelectHandler() {
			@Override
			public void onSelect(SelectEvent event) {
				TextButton b = (TextButton) event.getSource();
				TaskNode node = b.getData("node");
				if (node != null)
					presenter.goTo(new AppPlace(node.getId()));
			}
		};
		
		final SelectionHandler<Item> selectionHandler = new SelectionHandler<Item>() {
			@Override
			public void onSelection(SelectionEvent<Item> e) {
				TaskNode node = e.getSelectedItem().getData("node");
				if (node != null)
					presenter.goTo(new AppPlace(node.getId()));
			}
		};
		
		toolbar.mask("Loading Tasks...");
		menuService.getMenu(new Callback<List<TaskNode>>(toolbar) {
			@Override
			protected void handleSuccess(List<TaskNode> nodes) {
				for (int i = 0; i < toolbar.getWidgetCount(); i++)
					toolbar.remove(i--);
				
				for (int i = 0; i < nodes.size(); i++) {
					TaskNode node = nodes.get(i);
					TextButton button = createButton(node);
					
					toolbar.add(button);
					
					if (i < nodes.size() - 1)
						toolbar.add(new SeparatorToolItem());
					
					if (node.getType() == NodeType.BUTTON) {
						button.addSelectHandler(buttonHandler);
					} else {
						List<TaskNode> children = node.getChildren();
						if (children != null && !children.isEmpty()) {
							Menu menu = new Menu();
							button.setMenu(menu);
							
							for (TaskNode child : children) {
								final MenuItem item = createMenuItem(child);
								menu.add(item);
								
								item.addSelectionHandler(selectionHandler);
							}
						}
					}
				} // end-for
				
				// Very important to call this
				toolbar.forceLayout();
			} 
		});
	}
	
	private TextButton createButton(TaskNode node) {
		TextButton button = new TextButton(node.getText());
		button.setData("node.id", node.getId());
		button.setData("node", node);
		
		ImageResource img = iconProvider == null ? null : iconProvider.getIcon(node);
		if (img != null)
			button.setIcon(img);
		return button;
	}
	
	private MenuItem createMenuItem(TaskNode node) {
		final MenuItem item = new MenuItem(node.getText());
		item.setData("node.id", node.getId());
		item.setData("node", node);
		ImageResource img = iconProvider == null ? null : iconProvider.getIcon(node);
		if (img != null)
			item.setIcon(img);
		return item;
	}
	
	protected TaskNode findNode(String id) {
		for (int i = 0; i < toolbar.getWidgetCount(); i++) {
			Widget w = toolbar.getWidget(i);
			if (w instanceof TextButton) {
				TextButton tb = (TextButton) w;
				TaskNode node = tb.getData("node");
				if (node != null && node.getId().equals(id)) {
					return node;
				}
				
				if (node.getChildren() != null) {
					for (TaskNode child : node.getChildren())
						if (child.getId().equals(id))
							return child;
				}
			}
		}
		
		return null;
	}
	
	@Override
	public void onPlaceChange(PlaceChangeEvent e) {
		
	}

	@Override
	public void setPresenter(Presenter presenter) {
		this.presenter = presenter;
	}
	
	@UiFactory
	public ValueProvider<TaskNode, String> createValueProvider() {
		return new ValueProvider<TaskNode, String>() {
			@Override
			public String getValue(TaskNode object) {
				return object.getText();
			}

			@Override
			public void setValue(TaskNode object, String value) {
			}

			@Override
			public String getPath() {
				return "name";
			}
		};
	}

	// Inner classes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	static class KeyProvider implements ModelKeyProvider<TaskNode> {
		@Override
		public String getKey(TaskNode item) {
			return item.getId();
		}
	}

}
